package yanjun.tool.validate.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import yanjun.tool.validate.util.ReflectUtils;
import yanjun.tool.validate.util.ValidateFailErrorMessageBuilder;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.util.Set;

public class CGLibValidateProxy implements ValidateProxy {

    private Validator validator;

    public CGLibValidateProxy(Validator validator)
    {
        this.validator=validator;
    }

    @Override
    public Object generateProxy(Object target)
    {
        Enhancer eh = new Enhancer();

        eh.setSuperclass(target.getClass());

        eh.setCallback(new ValidateMethodInterceptor(validator));

        return eh.create();
    }

    private static class ValidateMethodInterceptor implements MethodInterceptor
    {
        private Validator validator;

        public ValidateMethodInterceptor(Validator validator)
        {
            this.validator=validator;
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            if(ReflectUtils.hasAnnotationArgument(method, Valid.class))
            {
                Set<ConstraintViolation<Object>> constraintViolations = validator.validate(objects[0]);
                if(constraintViolations.size()>0)
                {
                    String errorMessage= ValidateFailErrorMessageBuilder.build(constraintViolations);
                    throw new IllegalArgumentException(errorMessage);
                }
            }
            Object invoke = methodProxy.invokeSuper(o, objects);
            return invoke;
        }
    }
}
